﻿#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using Csla;
    using Csla.Data;
    using Csla.Reflection;
    using Csla.Server;

    using MarketPulse.BusinessLogic.Common;
    using MarketPulse.BusinessLogic.Common.Criteria;
    using Private = MarketPulse.BusinessLogic.Private;

    using MarketPulse.DataAccess.DataContextObjects.Production;

#endregion

namespace MarketPulse.DataAccess.Factory
{
    /// <summary>
    /// Abstracts the data access for all Assignment related objects (including Info and InfoList) away from their related business objects.
    /// </summary>
    public class AssignmentFactory : ObjectFactory
    {
        #region Member Variables

            /// <summary>
            /// Property that stores the name of the class.
            /// </summary>
            private static readonly Type mClass = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;

            /// <summary>
            /// Property that stores the log4net logger for this class.
            /// </summary>
            private static readonly log4net.ILog mLog = log4net.LogManager.GetLogger(mClass);

        #endregion

        #region Methods

            #region Create Methods

                #region AssignmentEvent

                    /// <summary>
                    /// Method used to create and return a new AssignmentEvent object instance
                    /// </summary>
                    /// <returns>The newly created AssignmentEvent object</returns>
                    [RunLocal]
                    public Private.AssignmentEvent CreateEvent()
                    {
                        // Create a new instance of the object
                        var assignmentEvent = (Private.AssignmentEvent)MethodCaller.CreateInstance(typeof(Private.AssignmentEvent));

                        // Mark it as a new object
                        MarkNew(assignmentEvent);
                        CheckRules(assignmentEvent);

                        MarkAsChild(assignmentEvent);

                        return assignmentEvent;
                    }

                #endregion

                #region AssignmentPayment

                    /// <summary>
                    /// Method used to create and return a new AssignmentPayment object instance
                    /// </summary>
                    /// <returns>The newly created AssignmentPayment object</returns>
                    [RunLocal]
                    public Private.AssignmentPayment CreatePayment()
                    {
                        // Create a new instance of the object
                        var assignmentPayment = (Private.AssignmentPayment)MethodCaller.CreateInstance(typeof(Private.AssignmentPayment));

                        // Mark it as a new object
                        MarkNew(assignmentPayment);
                        CheckRules(assignmentPayment);

                        MarkAsChild(assignmentPayment);

                        return assignmentPayment;
                    }

                #endregion

            #endregion

            #region Fetch Methods

                #region Assignment

                    /// <summary>
                    /// Method used to retrieve an existing Assignment from the database based on the Guid supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid and VersionId of the Assignment to retrieve</param>
                    /// <returns>The Assignment object retrieved from the database</returns>
                    public Private.Assignment Fetch(UniqueAssignmentCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var assignment = (Private.Assignment)MethodCaller.CreateInstance(typeof(Private.Assignment));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspAssignmentSelectByGUIDAndVersionID(criteria.Guid, criteria.VersionID);

                                // Get the result
                                UspAssignmentSelectByGUIDAndVersionIDResult result = null;
                                try
                                {
                                    result = selectResult.Single();
                                }
                                catch (InvalidOperationException ioe)
                                {
                                    // Construct error message
                                    StringBuilder errorMessage = new StringBuilder();
                                    errorMessage.Append("Unable to locate exactly one Assignment with Guid = [ ");
                                    errorMessage.Append(criteria.Guid);
                                    errorMessage.Append(" and VersionId = [ ");
                                    errorMessage.Append(criteria.VersionID);
                                    errorMessage.Append(" ]");
                                    mLog.Error(errorMessage.ToString(), ioe);
                                    throw new DataAccessException(errorMessage.ToString());
                                }

                                // Common properties inherited from MarketPulseBase<Visit>
                                LoadProperty(assignment, Private.Assignment.GUIDProperty, criteria.Guid);
                                LoadProperty(assignment, Private.Assignment.ObsoleteProperty, result.Obsolete.Value);
                                LoadProperty(assignment, Private.Assignment.InsertDateTimeProperty, result.InsertDateTime.Value);
                                LoadProperty(assignment, Private.Assignment.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                LoadProperty(assignment, Private.Assignment.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                LoadProperty(assignment, Private.Assignment.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                // Other properties
                                LoadProperty(assignment, Private.Assignment.mVersionIdProperty, criteria.VersionID);
                                LoadProperty(assignment, Private.Assignment.mUserGuidProperty, result.UserGUID);
                                LoadProperty(assignment, Private.Assignment.mRoundGuidProperty, result.RoundGUID);
                                LoadProperty(assignment, Private.Assignment.mBranchGuidProperty, result.BranchGUID);
                                LoadProperty(assignment, Private.Assignment.mResponseGuidProperty, result.ResponseGUID);
                                LoadProperty(assignment, Private.Assignment.mSurveyGuidProperty, result.SurveyGUID);
                                LoadProperty(assignment, Private.Assignment.mAssignmentStatusTypeGuidProperty, result.VisitStatusTypeGUID);
                                LoadProperty(assignment, Private.Assignment.mValidStartDateTimeProperty, result.ValidStartDateTime);
                                LoadProperty(assignment, Private.Assignment.mValidEndDateTimeProperty, result.ValidEndDateTime);
                                LoadProperty(assignment, Private.Assignment.mPlannedDateTimeProperty, result.PlannedDateTime);
                                LoadProperty(assignment, Private.Assignment.mActualStartDateTimeProperty, result.ActualStartDateTime);
                                LoadProperty(assignment, Private.Assignment.mActualEndDateTimeProperty, result.ActualEndDateTime);
                                LoadProperty(assignment, Private.Assignment.mLabelProperty, result.VisitLabel);

                                int dataEntryLag = Convert.ToInt32(result.DataEntryPeriod.Value);

                                LoadProperty(assignment, Private.Assignment.mDataEntryLagProperty, new TimeSpan(dataEntryLag, 0, 0));

                                // Set the survey version ID if it has a value
                                if (result.SurveyVersionID.HasValue)
                                {
                                    LoadProperty(assignment, Private.Assignment.mSurveyVersionIdProperty, result.SurveyVersionID.Value);
                                }
                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(assignment);

                                return assignment;
                            }
                        }
                        catch (DataAccessException dae)
                        {
                            mLog.Error(dae.ToString());
                            throw dae;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region AssignmentList

                    /// <summary>
                    /// Method used to fetch a read only list of Assignment objects from the database based on the criteria supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the values used to retrieve the list</param>
                    /// <returns>A list of Assignment objects retrieved from the database</returns>
                    public Private.AssignmentList FetchList(AssignmentSearchCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var assignmentList = (Private.AssignmentList)MethodCaller.CreateInstance(typeof(Private.AssignmentList));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspAssignmentSearch(criteria.ClientGuid, criteria.CountryGuid);

                                foreach (UspAssignmentSearchResult result in selectResult)
                                {
                                    Private.Assignment assignment = (Private.Assignment)MethodCaller.CreateInstance(typeof(Private.Assignment));

                                    // Common properties inherited from MarketPulseBase<Visit>
                                    LoadProperty(assignment, Private.Assignment.GUIDProperty, result.AssignmentGUID);
                                    LoadProperty(assignment, Private.Assignment.ObsoleteProperty, result.Obsolete.Value);
                                    LoadProperty(assignment, Private.Assignment.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(assignment, Private.Assignment.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    LoadProperty(assignment, Private.Assignment.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                    LoadProperty(assignment, Private.Assignment.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                    // Other properties
                                    LoadProperty(assignment, Private.Assignment.mVersionIdProperty, result.AssignmentVersionID);
                                    LoadProperty(assignment, Private.Assignment.mUserGuidProperty, result.UserGUID);
                                    LoadProperty(assignment, Private.Assignment.mRoundGuidProperty, result.RoundGUID);
                                    LoadProperty(assignment, Private.Assignment.mBranchGuidProperty, result.BranchGUID);
                                    LoadProperty(assignment, Private.Assignment.mResponseGuidProperty, result.ResponseGUID);
                                    LoadProperty(assignment, Private.Assignment.mSurveyGuidProperty, result.SurveyGUID);
                                    LoadProperty(assignment, Private.Assignment.mAssignmentStatusTypeGuidProperty, result.AssignmentStatusTypeGUID);
                                    LoadProperty(assignment, Private.Assignment.mValidStartDateTimeProperty, result.ValidStartDateTime);
                                    LoadProperty(assignment, Private.Assignment.mValidEndDateTimeProperty, result.ValidEndDateTime);
                                    LoadProperty(assignment, Private.Assignment.mPlannedDateTimeProperty, result.PlannedDateTime);
                                    LoadProperty(assignment, Private.Assignment.mActualStartDateTimeProperty, result.ActualStartDateTime);
                                    LoadProperty(assignment, Private.Assignment.mActualEndDateTimeProperty, result.ActualEndDateTime);
                                    LoadProperty(assignment, Private.Assignment.mLabelProperty, result.AssignmentLabel);

                                    int dataEntryLag = Convert.ToInt32(result.DataEntryPeriod.Value);

                                    LoadProperty(assignment, Private.Assignment.mDataEntryLagProperty, new TimeSpan(dataEntryLag, 0, 0));

                                    // Set the survey version ID if it has a value
                                    if (result.SurveyVersionID.HasValue)
                                    {
                                        LoadProperty(assignment, Private.Assignment.mSurveyVersionIdProperty, result.SurveyVersionID.Value);
                                    }

                                    // Mark the Assignment as a child element
                                    MarkAsChild(assignment);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(assignment);

                                    // Add the item to the list
                                    assignmentList.Add(assignment);
                                }

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(assignmentList);

                                return assignmentList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region AssignmentInfoList

                    /// <summary>
                    /// Method used to fetch a read only list of read only Assignment objects from the database based on the criteria supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the values used to retrieve the list</param>
                    /// <returns>A read only list of read only Assignment objects retrieved from the database</returns>
                    public AssignmentInfoList FetchInfoList(AssignmentSearchCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var assignmentInfoList = (AssignmentInfoList)MethodCaller.CreateInstance(typeof(AssignmentInfoList));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspAssignmentSearch(criteria.ClientGuid, criteria.CountryGuid);

                                // AssignmentInfoList is a read-only collection,
                                // so typically, when the data access is implemented in
                                // DataPortal_Fetch within the business object, the
                                // private IsReadOnly property must be set false in order to 
                                // populate the collection.  Here, within a factory,
                                // it isn't visible so one must resort to calling the 
                                // SetIsReadOnly method provided by our parent, ObjectFactory.
                                SetIsReadOnly(assignmentInfoList, false);
                                foreach (UspAssignmentSearchResult result in selectResult)
                                {
                                    AssignmentInfo assignmentInfo = (AssignmentInfo)MethodCaller.CreateInstance(typeof(AssignmentInfo));

                                    // Common properties inherited from MarketPulseBase
                                    LoadProperty(assignmentInfo, AssignmentInfo.GUIDProperty, result.AssignmentGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.ObsoleteProperty, result.Obsolete.Value);
                                    LoadProperty(assignmentInfo, AssignmentInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(assignmentInfo, AssignmentInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    LoadProperty(assignmentInfo, AssignmentInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                    LoadProperty(assignmentInfo, AssignmentInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                    // Other properties
                                    LoadProperty(assignmentInfo, AssignmentInfo.mUserGuidProperty, result.UserGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mRoundGuidProperty, result.RoundGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mBranchGuidProperty, result.BranchGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mResponseGuidProperty, result.ResponseGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mSurveyGuidProperty, result.SurveyGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mAssignmentStatusTypeGuidProperty, result.AssignmentStatusTypeGUID);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mValidStartDateTimeProperty, result.ValidStartDateTime);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mValidEndDateTimeProperty, result.ValidEndDateTime);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mPlannedDateTimeProperty, result.PlannedDateTime);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mActualStartDateTimeProperty, result.ActualStartDateTime);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mActualEndDateTimeProperty, result.ActualEndDateTime);

                                    LoadProperty(assignmentInfo, AssignmentInfo.mLabelProperty, result.AssignmentLabel);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mClientLabelProperty, result.ClientLabel);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mBranchLabelProperty, result.BranchLabel);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mUserLabelProperty, result.UserLabel);
                                    LoadProperty(assignmentInfo, AssignmentInfo.mStatusLabelProperty, result.AssignmentStatusLabel);

                                    // Set the assignment version ID if it has a value
                                    if (result.AssignmentVersionID.HasValue)
                                    {
                                        LoadProperty(assignmentInfo, AssignmentInfo.mVersionIdProperty, result.AssignmentVersionID.Value);
                                    }

                                    // Set the survey version ID if it has a value
                                    if (result.SurveyVersionID.HasValue)
                                    {
                                        LoadProperty(assignmentInfo, AssignmentInfo.mSurveyVersionIdProperty, result.SurveyVersionID.Value);
                                    }

                                    //CheckRules(visitInfo);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(assignmentInfo);

                                    // Add the item to the list
                                    assignmentInfoList.Add(assignmentInfo);
                                }
                                SetIsReadOnly(assignmentInfoList, true);

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(assignmentInfoList);

                                return assignmentInfoList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region AssignmentEventList

                    /// <summary>
                    /// Method used to fetch a list of AssignmentEvents associated with this Assignment from 
                    /// the database given a the Assignment GUID
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid of the Assignment to retrieve the list for</param>
                    /// <returns>The collection of AssignmentEvents fetched from the database</returns>
                    public Private.AssignmentEventList FetchAssignmentEventList(SingleCriteria<Guid> criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                var eventList = (Private.AssignmentEventList)MethodCaller.CreateInstance(typeof(Private.AssignmentEventList));

                                var selectResult = manager.DataContext.UspVisitEventSelectByVisitGUID(criteria.Value);

                                eventList.RaiseListChangedEvents = false;
                                foreach (UspVisitEventSelectByVisitGUIDResult result in selectResult)
                                {
                                    Private.AssignmentEvent assignmentEvent = (Private.AssignmentEvent)MethodCaller.CreateInstance(typeof(Private.AssignmentEvent));

                                    // Common properties inherited from MarketPulseBase<Assignment>
                                    LoadProperty(assignmentEvent, Private.AssignmentEvent.GUIDProperty, result.VisitEventGUID);
                                    LoadProperty(assignmentEvent, Private.AssignmentEvent.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(assignmentEvent, Private.AssignmentEvent.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    // Other properties
                                    LoadProperty(assignmentEvent, Private.AssignmentEvent.mAssignmentGuidProperty, criteria.Value);
                                    LoadProperty(assignmentEvent, Private.AssignmentEvent.mAssignmentEventTypeGUIDProperty, result.VisitEventTypeGUID);

                                    // Mark the Assignment Event as a child element
                                    MarkAsChild(assignmentEvent);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(assignmentEvent);

                                    // Add the item to the list
                                    eventList.Add(assignmentEvent);
                                }
                                eventList.RaiseListChangedEvents = true;

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(eventList);

                                return eventList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region AssignmentPaymentList

                    /// <summary>
                    /// Method used to fetch a list of AssignmentPayments associated with this Assignment from 
                    /// the database given a the Assignment Guid
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid of the Assignment to retrieve the list for</param>
                    /// <returns>The collection of AssignmentPayments fetched from the database</returns>
                    public Private.AssignmentPaymentList FetchAssignmentPaymentList(UniqueAssignmentCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                var eventList = (Private.AssignmentPaymentList)MethodCaller.CreateInstance(typeof(Private.AssignmentPaymentList));

                                var selectResult = manager.DataContext.UspVisitPaymentSelectByAssignmentGuidAndAssignmentVersionId(criteria.Guid, criteria.VersionID);

                                eventList.RaiseListChangedEvents = false;
                                foreach (UspVisitPaymentSelectByAssignmentGuidAndAssignmentVersionIdResult result in selectResult)
                                {
                                    Private.AssignmentPayment assignmentPayment = (Private.AssignmentPayment)MethodCaller.CreateInstance(typeof(Private.AssignmentPayment));

                                    // Common properties inherited from MarketPulseBase
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.GUIDProperty, result.AssignmnetPaymentGUID);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.ObsoleteProperty, result.Obsolete.Value);
                                    // Other properties
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.mAssignmentGuidProperty, criteria.Guid);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.mAssignmentVersionIdProperty, criteria.VersionID);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.mAssignmentPaymentTypeGuidProperty, result.PaymentTypeGUID);
                                    LoadProperty(assignmentPayment, Private.AssignmentPayment.mPaymentAmountProperty, (double)result.AssignmnetPaymentAmount.Value);

                                    // Mark the Assignment Event as a child element
                                    MarkAsChild(assignmentPayment);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(assignmentPayment);

                                    // Add the item to the list
                                    eventList.Add(assignmentPayment);
                                }
                                eventList.RaiseListChangedEvents = true;

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(eventList);

                                return eventList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region AssignmentEventList

                    /// <summary>
                    /// Method used to fetch a list of AssignmentEvents associated with this Assignment from 
                    /// the database given a the Assignment GUID
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid of the Assignment to retrieve the list for</param>
                    /// <returns>The collection of AssignmentEvents fetched from the database</returns>
                    public AssignmentStatusTypeList FetchAssignmentStatusTypeList()
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                var statusList = (AssignmentStatusTypeList)MethodCaller.CreateInstance(typeof(AssignmentStatusTypeList));

                                var selectResult = manager.DataContext.UspVisitStatusTypeSelectAll();

                                // NameValueListBase is a read-only collection,
                                // so typically, when the data access is implemented in
                                // DataPortal_Fetch within the business object, the
                                // private IsReadOnly property must be set false in order to 
                                // populate the collection.  Here, within a factory 
                                // , it isn't visible so one must resort to calling the 
                                // SetIsReadOnly method provided by our parent, ObjectFactory.
                                SetIsReadOnly(statusList, false);

                                foreach (UspVisitStatusTypeSelectAllResult result in selectResult)
                                {
                                    AssignmentStatusTypeList.NameValuePair nameValuePair = new AssignmentStatusTypeList.NameValuePair(result.VisitStatusTypeGUID.Value, result.VisitStatusTypeName);
                                    statusList.Add(nameValuePair);
                                }

                                SetIsReadOnly(statusList, true);

                                return statusList;
                            }

                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

            #endregion

            #region Update Methods

                /// <summary>
                /// Method used to persist an altered Visit object in the database.
                /// </summary>
                /// <param name="visit">The visit object to persist.</param>
                /// <returns>The Visit object potentially altered by the act of persisting it.</returns>
                [Transactional(TransactionalTypes.TransactionScope)]
                public Private.Assignment Update(Private.Assignment assignment)
                {
                    using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                    {
                        // Set up some local variables to hold the return values from the stored procedure calls
                        Nullable<Guid> userGUID = assignment.ActionUserGUID;
                        Nullable<DateTime> dateTime = null;
                        Nullable<Guid> guid = assignment.GUID.HasValue ? assignment.GUID : null;

                        if (assignment.IsDirty)
                        {
                            // Set default time for anything happening next
                            dateTime = DateTime.Now;

                            // TODO update assignment including any changes to assignment event type
                            BusinessLogic.Private.Response response = assignment.Response;
                            if (response != null)
                            {
                                if (response.IsNew)
                                {
                                    // Insert the new Response record
                                    manager.DataContext.UspResponseInsert(ref guid, assignment.Survey.GUID, assignment.Survey.VersionID, response.ResponseXML, null, userGUID, ref dateTime);

                                    // Load the new values into the Response object
                                    LoadProperty(response, BusinessLogic.Private.Response.GUIDProperty, guid.Value);
                                    LoadProperty(response, BusinessLogic.Private.Response.InsertDateTimeProperty, dateTime.Value);
                                    LoadProperty(response, BusinessLogic.Private.Response.InsertUserGUIDProperty, userGUID.Value);
                                    LoadProperty(response, BusinessLogic.Private.Response.UpdateDateTimeProperty, dateTime.Value);
                                    LoadProperty(response, BusinessLogic.Private.Response.UpdateUserGUIDProperty, userGUID.Value);
                                    // Set the Visit object to know it's set of Responses
                                    LoadProperty(assignment, BusinessLogic.Private.Visit.ResponseGUIDProperty, response.GUID);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(response);
                                }
                                else if (response.IsDirty)
                                {
                                    // Update the existing Response record
                                    manager.DataContext.UspResponseUpdate(response.GUID, assignment.SurveyGuid, assignment.SurveyVersionId, response.ResponseXML, null, userGUID, ref dateTime);

                                    // Load the updated values into the Response object
                                    LoadProperty(response, BusinessLogic.Private.Response.UpdateDateTimeProperty, dateTime.Value);
                                    LoadProperty(response, BusinessLogic.Private.Response.UpdateUserGUIDProperty, userGUID.Value);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(response);
                                }
                            }

                            // Check the rules for this assignment before going further.
                            CheckRules(assignment);
                            if (assignment.BrokenRulesCollection.Count > 0)
                            {
                                // TODO: JSR: why this?
                                return assignment;
                            }

                            BusinessLogic.Private.AssignmentEventList events = assignment.Events;
                            if (events.IsDirty)
                            {
                                // TODO find a cleaner way of inserting assignments, walking the list doesn't feel right!
                                // Loop thorought the events list and save dirty one's
                                foreach (var assignmentEvent in assignment.Events)
                                {
                                    if (assignmentEvent.IsNew)
                                    {
                                        // Insert a new Visit Event record
                                        manager.DataContext.UspVisitEventInsert(ref guid, assignmentEvent.AssignmentGuid, assignmentEvent.AssignmentEventTypeGuid, userGUID, ref dateTime);

                                        // Load the inserted values into the Visit Event object                                    
                                        LoadProperty(assignmentEvent, BusinessLogic.Private.AssignmentEvent.GUIDProperty, guid.Value);
                                        LoadProperty(assignmentEvent, BusinessLogic.Private.AssignmentEvent.InsertDateTimeProperty, dateTime.Value);
                                        LoadProperty(assignmentEvent, BusinessLogic.Private.AssignmentEvent.InsertUserGUIDProperty, userGUID.Value);
                                        LoadProperty(assignmentEvent, BusinessLogic.Private.AssignmentEvent.UpdateDateTimeProperty, dateTime.Value);
                                        LoadProperty(assignmentEvent, BusinessLogic.Private.AssignmentEvent.UpdateUserGUIDProperty, userGUID.Value);

                                        // Make sure that CSLA thinks this *hasn't* changed since being instantiated
                                        MarkOld(assignmentEvent);
                                    }
                                }
                            }

                            BusinessLogic.Private.AssignmentPaymentList payments = assignment.Payments;
                            if (payments.IsDirty)
                            {
                                // Update payments
                                foreach (var assignmentPayment in assignment.Payments)
                                {
                                    if (assignmentPayment.IsDirty)
                                    {
                                        manager.DataContext.UspAssignmentPaymentUpdate(assignmentPayment.GUID, (decimal)assignmentPayment.Amount, userGUID, ref dateTime);

                                        LoadProperty(assignmentPayment, BusinessLogic.Private.AssignmentPayment.UpdateDateTimeProperty, dateTime.Value);
                                        LoadProperty(assignmentPayment, BusinessLogic.Private.AssignmentPayment.UpdateUserGUIDProperty, userGUID.Value);

                                        // Make sure that CSLA thinks this *hasn't* changed since being instantiated
                                        MarkOld(assignmentPayment);
                                    }
                                }
                            }

                            // Update the existing Visit record
                            manager.DataContext.UspVisitUpdate(assignment.GUID, assignment.VersionId, assignment.RoundGuid, assignment.UserGuid, assignment.BranchGuid, assignment.ResponseGuid, assignment.SurveyGuid, assignment.SurveyVersionId, assignment.AssignmentStatusTypeGuid,
                                                                assignment.ValidStartDateTime, assignment.ValidEndDateTime, assignment.PlannedDateTime, assignment.ActualStartDateTime, assignment.ActualEndDateTime, null, userGUID, ref dateTime);

                            // Load the updated values into the Visit object
                            LoadProperty(assignment, Private.Assignment.UpdateDateTimeProperty, dateTime.Value);
                            LoadProperty(assignment, Private.Assignment.UpdateUserGUIDProperty, userGUID.Value);

                            // Make sure that CSLA knows this has changed since being instantiated
                            MarkOld(assignment);
                        }

                        return assignment;
                    }
                }

            #endregion

        #endregion

    }
}
